package com.aoyy.dao;

import java.io.Serializable;
import java.util.Map;
import java.util.List;
import java.util.Set;
import java.lang.StringBuffer;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import com.aoyy.util.Generics;
import com.aoyy.util.Pagination;
/**===================================================================================================
 * <code>BaseDaoImpl<T></code> class for the implementations of <code>IBaseDao<T></code> interface
 * @author Administrator
 * @date 2017-07-13
 * @param <T>
 * ==================================================================================================== */
@SuppressWarnings("unchecked")
@Transactional
public class BaseDaoImpl<T> implements IBaseDao<T> {
  protected Class<T> entityClass = (Class<T>) Generics.getGenericType(this.getClass());
  
  @Autowired
  @Qualifier("sessionFactory")
  private SessionFactory sessionFactory;
  protected Session getSession() {
	return sessionFactory.getCurrentSession();  
  }
  
  @Override
  public void save(Object object) {
	getSession().save(object);	
  }

  @Override
  public void saveOrUpdate(Object object) {
    getSession().saveOrUpdate(object);
  }
  
  @Override
  public void update(Object object) {
    getSession().update(object);
  }
  
  @Override
  public void delete(Serializable... ids) {
	for (Serializable id: ids) {
	  T t = (T) getSession().load(this.entityClass, id);
      getSession().delete(t);
    }
  }

  @Override
  @Transactional(propagation=Propagation.NOT_SUPPORTED, readOnly=true)
  public T get(Serializable entityId) {
    T t = (T) getSession().get(this.entityClass, entityId);
    return t;
  }

  @Override
  @Transactional(propagation=Propagation.NOT_SUPPORTED, readOnly=true)
  public T load(Serializable entityId) {
	T t = (T) getSession().load(this.entityClass, entityId);
	return t;
  }

  @Override
  @Transactional(propagation=Propagation.NOT_SUPPORTED, readOnly=true)
  public Object uniqueResult(String hql, Object[] parameters) {
	Query query = this.getSession().createQuery(hql);
	if (parameters != null && parameters.length > 0) {
	  int length = parameters.length;
	  for (int i = 0; i < length; i++) {
		query.setParameter(i, parameters[i]); 
	  }
	}
	return query.uniqueResult();
  }

  @Override
  @Transactional(propagation=Propagation.NOT_SUPPORTED, readOnly=true)
  public Integer getRecordCount() {
    String hql = "select count(*) from " + this.entityClass.getName();
    return ((Long) uniqueResult(hql, null)).intValue();
  }
  
  @Override
  @Transactional(propagation=Propagation.NOT_SUPPORTED, readOnly=true)
  public Pagination<T> query(Integer pageNo, Integer pageSize) {
	return this.query(null, null, null, pageNo, pageSize);
  }
  
  @Override
  @Transactional(propagation=Propagation.NOT_SUPPORTED, readOnly=true)
  public Pagination<T> query(String where, Object[] parameters, Integer pageNo, Integer pageSize) {
	return this.query(where, parameters, null, pageNo, pageSize);
  }

  @Override
  @Transactional(propagation=Propagation.NOT_SUPPORTED, readOnly=true)
  public Pagination<T> query(Map<String, String> orderby, Integer pageNo, Integer pageSize) {
	return this.query(null, null, orderby, pageNo, pageSize);
  }

  @Override
  @Transactional(propagation=Propagation.NOT_SUPPORTED, readOnly=true)
  public Pagination<T> query(String where, Object[] parameters, Map<String, String> orderby, Integer pageNo, Integer pageSize) {
    Pagination<T> pagination = new Pagination<T>();
    pagination.setPageNo(pageNo);
    pagination.setPageSize(pageSize);
    String hql = new StringBuffer().append("from ").append(this.entityClass.getName()).append(" ")
          .append((where == null) ? "" : where).append(" ")
          .append(this.createOrderby(orderby)).toString();
    Query query = this.getSession().createQuery(hql);
    if (parameters != null && parameters.length > 0) {
      int length = parameters.length;
      for (int i = 0; i < length; i++) {
    	query.setParameter(i, parameters[i]);  
      }
    }
    List<T> list = null;
    if (pageNo < 0 && pageSize < 0) {
      list = query.list();	
    } else {
      list = query.setFirstResult(this.getFirstResult(pageNo, pageSize)).setMaxResults(pageSize).list();
      hql = new StringBuffer().append("select count(*) from ").append(this.entityClass.getName()).append(" ")
    		  .append((where == null) ? "" : where).toString();
      query = getSession().createQuery(hql);
      if (parameters != null && parameters.length > 0) {
    	int length = parameters.length;
    	for (int i = 0; i < length; i++) {
          query.setParameter(i, parameters[i]);		
    	}
      }
      Integer recordCount = ((Long) query.uniqueResult()).intValue();
      pagination.setRecordCount(recordCount);
    }
    pagination.setList(list);
    return pagination;
  }
  	
  protected Integer getFirstResult(Integer pageNo, Integer pageSize) {
	Integer firstResult = (pageNo - 1) * pageSize;  
	return (firstResult < 0) ? 0 : firstResult; 
  }
  
  /**=========================================================================================
   * <code>createOrderby</code>method to create <code>order by</code> query statement
   * @param {Map<String, String>} orderby
   * @return {String} 
   * ========================================================================================== */
  protected String createOrderby(Map<String, String> orderby) {
	StringBuffer buffer = new StringBuffer();
	if (orderby != null && orderby.size() > 0) {
	  buffer.append("order by ");
	  Set<String> keys = orderby.keySet();
	  for (String key: keys) {
		buffer.append(key).append(" ").append(orderby.get(key)).append(",");  
	  }
	  buffer.deleteCharAt(buffer.length() - 1);
	}
	return buffer.toString();  
  }
    
}
